/*
 * Copyright the original author or authors.
 * 
 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *	  http://www.mozilla.org/MPL/MPL-1.1.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 package com.googlecode.milib.service.singleton {
	import com.googlecode.milib.MILibMain;
	import com.googlecode.milib.base.MLBroadcastClass;

	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.KeyboardEvent;

	/**
	 * @author Marek Brun
	 */
	public class KeyboardService extends MLBroadcastClass {
		
		/*DATA:	KeyboardEvent
		bubbles true 
		cancelable false; there is no default behavior to cancel. 
		charCode The character code value of the key pressed or released. 
		ctrlKey true if the Control key is active; false if it is inactive. 
		currentTarget The object that is actively processing the Event object with an event listener. 
		keyCode The key code value of the key pressed or released. 
		keyLocation The location of the key on the keyboard. 
		shiftKey true if the Shift key is active; false if it is inactive. 
		target The InteractiveObject instance with focus. The target is not always the object
			   in the display list that registered the event listener. Use the currentTarget property
			   to access the object in the display list that is currently processing the event. 
		*/
		public const event_Down : String = 'Down';
		
		//DATA:	<same as event_Down>
		public const event_Up : String = 'Up';
		
		public static const KEY_BACK:uint=8;		public static const KEY_TAB:uint=9;
		public static const KEY_SPACE:uint=32;
		public static const KEY_LEFT:uint=37;
		public static const KEY_RIGHT:uint=39;
		public static const KEY_UP:uint=38;
		public static const KEY_DOWN:uint=40;
		public static const KEY_ENTER:uint=13;
		public static const KEY_CTRL:uint=17;
		public static const KEY_SHIFT:uint=16;
		public static const KEY_ESC:uint=27;
		public static const KEY_A:uint=65;
		public static const KEY_B:uint=66;
		public static const KEY_C:uint=67;
		public static const KEY_D:uint=68;
		public static const KEY_E:uint=69;
		public static const KEY_F:uint=70;
		public static const KEY_G:uint=71;
		public static const KEY_H:uint=72;
		public static const KEY_I:uint=73;
		public static const KEY_J:uint=74;
		public static const KEY_K:uint=75;
		public static const KEY_L:uint=76;
		public static const KEY_M:uint=77;
		public static const KEY_N:uint=78;
		public static const KEY_O:uint=79;
		public static const KEY_P:uint=80;
		public static const KEY_Q:uint=81;
		public static const KEY_R:uint=82;
		public static const KEY_S:uint=83;
		public static const KEY_T:uint=84;
		public static const KEY_U:uint=85;
		public static const KEY_V:uint=86;
		public static const KEY_W:uint=87;
		public static const KEY_X:uint=88;
		public static const KEY_Y:uint=89;		public static const KEY_Z:uint=90;
		public static const KEY_0:uint=48;
		public static const KEY_TILDE:uint=192;
		public static const KEY_1:uint=49;
		public static const KEY_2:uint=50;
		public static const KEY_3:uint=51;
		public static const KEY_4:uint=52;
		public static const KEY_5:uint=53;
		public static const KEY_6:uint=54;
		public static const KEY_7:uint=55;
		public static const KEY_8:uint=56;
		public static const KEY_9:uint=57;
		public static const KEY_COMMA:uint=188;
		public static const KEY_DOT:uint=190;
		public static const KEY_F1:uint=112;
		public static const KEY_F2:uint=113;
		public static const KEY_F3:uint=114;
		public static const KEY_F4:uint=115;
		public static const KEY_F5:uint=116;
		public static const KEY_F6:uint=117;
		public static const KEY_F7:uint=118;
		public static const KEY_F8:uint=119;
		public static const KEY_F9:uint=120;
		public static const KEY_PAUSE:uint=19;
		public static const KEY_NUM_0:uint=96;
		public static const KEY_NUM_1:uint=97;
		public static const KEY_NUM_2:uint=98;
		public static const KEY_NUM_3:uint=99;
		public static const KEY_NUM_4:uint=100;
		public static const KEY_NUM_5:uint=101;
		public static const KEY_NUM_6:uint=102;
		public static const KEY_NUM_7:uint=103;
		public static const KEY_NUM_8:uint=104;
		public static const KEY_NUM_9:uint=105;		public static var KEY_ALT:uint=17;
		
		private static var instance:KeyboardService;		
		private var keyCodeAndIsDown:Array;
		public var lastKeyCode:uint;
		public var isAlt:Boolean;
		public var isCtrl:Boolean;
		public var isShift:Boolean;
		
		public function KeyboardService(access:Private) {
			var stage:Stage=MILibMain.getInstance().getStage();
			stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyboardDown, false, 0, true);
			stage.addEventListener(KeyboardEvent.KEY_UP, onKeyboardUp, false, 0, true);
			stage.addEventListener(Event.DEACTIVATE, onKeyboardDeactivate, false, 0, true);
			keyCodeAndIsDown=[];
		}
		
		public function getIsKeyDown(keyCode:uint):Boolean {
			return Boolean(keyCodeAndIsDown[keyCode]);
		}
		
		public function getKeysDown():Array {
			return keyCodeAndIsDown.concat();
		}
		
		public static function getInstance():KeyboardService {
			if(instance) { return instance; }
			else{ instance=new KeyboardService(null); return instance; }
		}
		
//********************************************************************************************
//		events for KeyboardService
//********************************************************************************************
		protected function onKeyboardDown(event:KeyboardEvent):void {
			if(keyCodeAndIsDown[event.keyCode]){ return; }
			lastKeyCode=event.keyCode;
			keyCodeAndIsDown[event.keyCode]=true;
			
			isAlt=event.altKey;			isCtrl=event.ctrlKey;			isShift=event.shiftKey;
			
			broadcastEvent(event_Down, event);
		}
		
		protected function onKeyboardUp(event:KeyboardEvent):void {
			if(!keyCodeAndIsDown[event.keyCode]){ return; }
			keyCodeAndIsDown[event.keyCode]=false;
			
			isAlt=event.altKey;
			isCtrl=event.ctrlKey;
			isShift=event.shiftKey;
			
			broadcastEvent(event_Up, event);
		}
		
		protected function onKeyboardDeactivate(event:Event):void {
			var i:uint;
			var loopIsDown:Boolean;
			for(i=0;i<keyCodeAndIsDown.length;i++){
				loopIsDown=keyCodeAndIsDown[i];
				if(loopIsDown){
					broadcastEvent(event_Up, new KeyboardEvent(KeyboardEvent.KEY_UP, false, false, NaN, i));
				}
				
			}
			keyCodeAndIsDown=[];
		}
		
	}
}

internal class Private {}
